package com.bii.gelapp;

import java.util.ArrayList;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;




import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

public class DNACalculateTouchImageView extends ImageView{
	
	Matrix matrix;
	// We can be in one of these 3 states
		static final int NONE = 0;
		static final int DRAG = 1;
		static final int ZOOM = 2;
		int mode = NONE;

		// modes
		public static boolean editmode = false;

		// Remember some things for zooming
		PointF last = new PointF();
		PointF start = new PointF();
		float minScale = 1f;
		float maxScale = 4f;
		float[] m;

		// circledrawing
		float instx;
		float insty;

		int viewWidth, viewHeight;
		static final int CLICK = 3;
		float saveScale = 1f;
		protected float origWidth, origHeight;
		int oldMeasuredWidth, oldMeasuredHeight;

		ScaleGestureDetector mScaleDetector;
		MarkerStandard mss;

		Context context;

		Bitmap bmap;
		 //export this bitmap
		public static Bitmap valuesbmp;
		Mat drawmat;
		ArrayList<ConnectedComponent> componentlist = new ArrayList<ConnectedComponent>();
		ArrayList<ConnectedComponent> markerlist = new ArrayList<ConnectedComponent>();
		ArrayList componentvalues = new ArrayList();
		ArrayList markervalues = new ArrayList();
		public Bitmap originalBmp;
		
		public DNACalculateTouchImageView(Context context, Bitmap bmp) {
			super(context);
			originalBmp = bmp;
			sharedConstructing(context);
		}
		
		private void sharedConstructing(Context context) {
			// preparation for all the image loading and stuffs
			super.setClickable(true);
			this.context = context;
			mss = StartActivity.ms;

			bmap = originalBmp;
			drawmat = new Mat(bmap.getHeight(), bmap.getWidth(), CvType.CV_8U);

			componentlist = DNACalculateFullscreenActivity.componentlist;
			markerlist = DNACalculateFullscreenActivity.markerlist;
			markervalues = DNACalculateFullscreenActivity.markervalues;
			if (DNACalculateFullscreenActivity.componentvalues.size() != 0) {
				componentvalues = DNACalculateFullscreenActivity.componentvalues;
			}

			mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
			matrix = new Matrix();
			m = new float[9];
			setImageMatrix(matrix);
			// allow scaling of image by matrix
			setScaleType(ScaleType.MATRIX);

			setOnTouchListener(new OnTouchListener() {

				@Override
				public boolean onTouch(View v, MotionEvent event) {
					mScaleDetector.onTouchEvent(event);
					PointF curr = new PointF(event.getX(), event.getY());

					switch (event.getAction()) {
					case MotionEvent.ACTION_DOWN:
						last.set(curr);
						start.set(last);
						mode = DRAG;
						
						if (editmode == true){
							Matrix inverse = new Matrix();
							getImageMatrix().invert(inverse);
							float[] touchPoint = new float[] { event.getX(),
									event.getY() };
							inverse.mapPoints(touchPoint);
							instx = touchPoint[0];
							insty = touchPoint[1];

						}
								
						break;

					case MotionEvent.ACTION_MOVE:
						if (mode == DRAG) {
							// get the new horizontal and vertical positions
							float deltaX = curr.x - last.x;
							float deltaY = curr.y - last.y;
							// if view width is larger than content size (original
							// width and height) returns 0
							float fixTransX = getFixDragTrans(deltaX, viewWidth,
									origWidth * saveScale);
							float fixTransY = getFixDragTrans(deltaY, viewHeight,
									origHeight * saveScale);
							matrix.postTranslate(fixTransX, fixTransY);
							fixTrans();
							last.set(curr.x, curr.y);
						}
						break;

					case MotionEvent.ACTION_UP:
						mode = NONE;
						int xDiff = (int) Math.abs(curr.x - start.x);
						int yDiff = (int) Math.abs(curr.y - start.y);
						if (xDiff < CLICK && yDiff < CLICK)
							performClick();
						
						if (editmode == true) {
							Point center = new Point(instx, insty);
							Log.d("tag1", "instx: " + instx + " insty: " + insty);
							Core.circle(drawmat, center, 10,  new Scalar(255, 0, 255));
							
							double distancetopmarker = insty - CalculateActivity2.topmarkercenter;	
							
							double wcd = distancetopmarker + CalculateActivity2.edw;
							double value = ScatterGraph.instantCalculate(wcd);
							
							Log.d("tag1", "distancetopmarker: " + distancetopmarker);
							Log.d("tag1", "edw: " + CalculateActivity2.edw);
							Log.d("tag1", "value: " + value);
							
							Point org = new Point(instx, insty);
							//float value = (Float) componentvalues.get(i);

							// String valuedisplay = " "+ value;
							String valuedisplay = String.format("%.1f", value);
							
							//DecimalFormat numberFormat = new DecimalFormat("#.00");
							//numberFormat.format(value);
							Core.putText(drawmat, "" + valuedisplay, org , 3, 0.75, new Scalar(255, 0 ,255), 1);
							
							Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
									Bitmap.Config.RGB_565);
							Utils.matToBitmap(drawmat, drawnbmp);
							setImageBitmap(drawnbmp);
						}
						break;

					case MotionEvent.ACTION_POINTER_UP:
						mode = NONE;
						break;
					}
					setImageMatrix(matrix);
					invalidate();
					return true; // indicate event was handled

				}

			});
			drawRectangles();

			if (componentvalues.size() == 0) {
				for (int i = 0; i < componentlist.size(); i++) {
					getValuesOfComponent(componentlist.get(i));
				}
			}

			// component values
			for (int i = 0; i < componentlist.size(); i++) {
				int top = componentlist.get(i).top;
				int bottom = componentlist.get(i).bottom;
				int left = componentlist.get(i).left;
				int right = componentlist.get(i).right;

				// int centerheight = (bottom + top)/2;
				int centerheight = bottom;
				// int centerwidth = (right + left)/2;
				int centerwidth = left;
				Point org = new Point(centerwidth, centerheight);

				float value = (Float) componentvalues.get(i);

				// String valuedisplay = " "+ value;
				String valuedisplay = String.format("%.1f", value);
				Core.putText(drawmat, valuedisplay, org, 3, 0.75, new Scalar(0, 0,
						255), 1);

				Log.d("tag1", "component " + i + "value: " + value + " center: "
						+ (top + bottom) / 2);

			}
			// marker values
			for (int i = 0; i < markerlist.size(); i++) {
				
				int top = markerlist.get(i).top;
				int bottom = markerlist.get(i).bottom;
				int left = markerlist.get(i).left;
				int right = markerlist.get(i).right;

				// int centerheight = (bottom + top)/2;
				int centerheight = bottom;
				// int centerwidth = (right + left)/2;
				int centerwidth = left;
				Point org = new Point(centerwidth, centerheight);

				//float value = (Float) markervalues.get(i);
				Integer value = (Integer)markervalues.get(i);
				String value1 = String.valueOf(value);
				
				// String valuedisplay = " "+ value;
				//String valuedisplay = String.format("%.1f", value1);
				Core.putText(drawmat, value1, org, 3, 0.75, new Scalar(0, 255,
						0), 1);
				
				/*
				int top = markerlist.get(i).top;
				int bottom = markerlist.get(i).bottom;
				int left = markerlist.get(i).left;
				int right = markerlist.get(i).right;

				// int centerheight = (bottom + top) / 2;
				// int centerwidth = (right + left) / 2;
				int centerheight = bottom;
				int centerwidth = left;
				Point org = new Point(centerwidth, centerheight);

				MarkerConnectedComponent mcc = mss.getmarkers().get(i);
				//int value = mcc.value;
				int value = (Integer) markervalues.get(i);
				
				String valuedisplay = " " + value;
				int[] msscolors = mss.getmarkers().get(i).color;
				int red = msscolors[0];
				int green = msscolors[1];
				int blue = msscolors[2];

				Core.putText(drawmat, valuedisplay, org, 3, 0.75, new Scalar(red,
						green, blue), 1);
				Log.d("tag1", "marker " + i + "value: " + valuedisplay
						+ " center: " + (top + bottom) / 2);
						*/
			}

			Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
					Bitmap.Config.RGB_565);
			Utils.matToBitmap(drawmat, drawnbmp);

			// Bitmap resizedbmp = Bitmap.createScaledBitmap(drawnbmp, 300, 300,
			// true);
			setImageBitmap(drawnbmp);
			valuesbmp = drawnbmp.copy(Config.ARGB_8888, true);
			/*
			 * Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
			 * Bitmap.Config.RGB_565); Utils.matToBitmap(drawmat, drawnbmp);
			 * setImageBitmap(drawnbmp);
			 */

		}
		
		public void setMaxZoom(float x) {
			maxScale = x;
		}

		private class ScaleListener extends
				ScaleGestureDetector.SimpleOnScaleGestureListener {
			@Override
			public boolean onScaleBegin(ScaleGestureDetector detector) {
				mode = ZOOM;
				return true;
			}

			@Override
			public boolean onScale(ScaleGestureDetector detector) {
				float mScaleFactor = detector.getScaleFactor();
				// original scale is 1 times, zooming means to multiply it by the
				// scalefactor
				float origScale = saveScale;
				saveScale *= mScaleFactor;

				if (saveScale > maxScale) {
					// prevent zooming in too much
					saveScale = maxScale;
					mScaleFactor = maxScale / origScale;
				} else if (saveScale < minScale) {
					// prevent zooming out too much
					saveScale = minScale;
					mScaleFactor = minScale / origScale;
				}

				if (origWidth * saveScale <= viewWidth
						|| origHeight * saveScale <= viewHeight)
					matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
							viewHeight / 2);
				else
					matrix.postScale(mScaleFactor, mScaleFactor,
							detector.getFocusX(), detector.getFocusY());

				fixTrans();
				return true;
			}
		}

		void fixTrans() {
			matrix.getValues(m);
			float transX = m[Matrix.MTRANS_X];
			float transY = m[Matrix.MTRANS_Y];

			float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
			float fixTransY = getFixTrans(transY, viewHeight, origHeight
					* saveScale);

			if (fixTransX != 0 || fixTransY != 0)
				matrix.postTranslate(fixTransX, fixTransY);
		}

		float getFixTrans(float trans, float viewSize, float contentSize) {
			float minTrans, maxTrans;

			if (contentSize <= viewSize) {
				minTrans = 0;
				maxTrans = viewSize - contentSize;
			} else {
				minTrans = viewSize - contentSize;
				maxTrans = 0;
			}

			if (trans < minTrans)
				return -trans + minTrans;
			if (trans > maxTrans)
				return -trans + maxTrans;
			return 0;
		}

		float getFixDragTrans(float delta, float viewSize, float contentSize) {
			if (contentSize <= viewSize) {
				return 0;
			}
			return delta;
		}

		@Override
		protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
			super.onMeasure(widthMeasureSpec, heightMeasureSpec);
			viewWidth = MeasureSpec.getSize(widthMeasureSpec);
			viewHeight = MeasureSpec.getSize(heightMeasureSpec);

			//
			// Rescales image on rotation
			//
			if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
					|| viewWidth == 0 || viewHeight == 0)
				return;
			oldMeasuredHeight = viewHeight;
			oldMeasuredWidth = viewWidth;

			if (saveScale == 1) {
				// Fit to screen.
				float scale;

				Drawable drawable = getDrawable();
				if (drawable == null || drawable.getIntrinsicWidth() == 0
						|| drawable.getIntrinsicHeight() == 0)
					return;
				int bmWidth = drawable.getIntrinsicWidth();
				int bmHeight = drawable.getIntrinsicHeight();

				Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

				float scaleX = (float) viewWidth / (float) bmWidth;
				float scaleY = (float) viewHeight / (float) bmHeight;
				scale = Math.min(scaleX, scaleY);
				matrix.setScale(scale, scale);

				// Center the image
				float redundantYSpace = (float) viewHeight
						- (scale * (float) bmHeight);
				float redundantXSpace = (float) viewWidth
						- (scale * (float) bmWidth);
				redundantYSpace /= (float) 2;
				redundantXSpace /= (float) 2;

				matrix.postTranslate(redundantXSpace, redundantYSpace);

				origWidth = viewWidth - 2 * redundantXSpace;
				origHeight = viewHeight - 2 * redundantYSpace;
				setImageMatrix(matrix);
			}
			fixTrans();
		}

		private void drawRectangles() {
			Utils.bitmapToMat(bmap, drawmat);
			for (int i = 0; i < componentlist.size(); i++) {
				Core.rectangle(drawmat, new Point(componentlist.get(i).left,
						componentlist.get(i).top), new Point(
						componentlist.get(i).right, componentlist.get(i).bottom),
						new Scalar(255, 0, 0), 2);
			}
			for (int i = 0; i < markerlist.size(); i++) {
				Core.rectangle(drawmat, new Point(markerlist.get(i).left,
						markerlist.get(i).top), new Point(markerlist.get(i).right,
						markerlist.get(i).bottom), new Scalar(255, 255, 0), 2);
			}
			Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
					Bitmap.Config.RGB_565);
			Utils.matToBitmap(drawmat, drawnbmp);
			setImageBitmap(drawnbmp);

		};
		
		private void getValuesOfComponent(ConnectedComponent cc) {
			ConnectedComponent cctop;
			ConnectedComponent ccbottom;
			int topindex = 0;
			int bottomindex = 1;
			float comparedifferencetop = 9999;
			float comparedifferencebottom = 9999;

			int cccenterheight = (cc.top + cc.bottom) / 2;

			for (int j = 0; j < markerlist.size(); j++) {
				if (j + 1 != markerlist.size()) {
					float comparetopcenter = (markerlist.get(j).top + markerlist
							.get(j).bottom) / 2;
					float comparebottomcenter = (markerlist.get(j + 1).top + markerlist
							.get(j + 1).bottom) / 2;
					if (comparedifferencetop == 9999
							&& comparedifferencebottom == 9999) {

						comparedifferencetop = Math.abs(cccenterheight
								- comparetopcenter);
						comparedifferencebottom = Math.abs(cccenterheight
								- comparebottomcenter);

						// comparedifferencetop = cccenterheight - comparetopcenter;
						// comparedifferencebottom = cccenterheight -
						// comparebottomcenter;
						cctop = markerlist.get(j);
						ccbottom = markerlist.get(j + 1);
						topindex = j;
						bottomindex = j + 1;
					} else {
						if (cccenterheight > comparetopcenter
								&& cccenterheight < comparebottomcenter) {
							float differencetop = Math.abs(cccenterheight
									- comparetopcenter);
							float differencebottom = Math.abs(cccenterheight
									- comparebottomcenter);

							// float differencetop = cccenterheight -
							// comparetopcenter;
							// float differencebottom = cccenterheight -
							// comparebottomcenter;

							if (differencetop < comparedifferencetop
									&& differencebottom < comparedifferencebottom) {
								comparedifferencetop = differencetop;
								comparedifferencebottom = differencebottom;
								cctop = markerlist.get(j);
								ccbottom = markerlist.get(j + 1);
								topindex = j;
								bottomindex = j + 1;
							} else {
								;
							}
						} else {
							;
						}
					}

				}
			}

			// MarkerConnectedComponent mcc = mss.getmarkers().get(i+lowestindex);
			//MarkerConnectedComponent mcctop = mss.getmarkers().get(topindex);
			//MarkerConnectedComponent mccbottom = mss.getmarkers().get(bottomindex);
			ConnectedComponent mcctop = markerlist.get(topindex);
			ConnectedComponent mccbottom = markerlist.get(bottomindex);
			//float topvalue = mcctop.value;
			//float bottomvalue = mccbottom.value;
			float topvalue = (Float) markervalues.get(topindex);
			float bottomvalue = (Float) markervalues.get(bottomindex);

			float power = 0;

			float powerleft = (float) Math.log10(bottomvalue);
			float powerrightone = (float) (Math.log10(topvalue) - Math
					.log10(bottomvalue));
			float powerrighttwo = comparedifferencebottom;
			// float powerrightthree = comparedifferencetop;
			float comparetopcenter = (markerlist.get(topindex).top + markerlist
					.get(topindex).bottom) / 2;
			float comparebottomcenter = (markerlist.get(bottomindex).top + markerlist
					.get(bottomindex).bottom) / 2;

			float powerrightthree = Math
					.abs(comparetopcenter - comparebottomcenter);
			// float powerright = powerrightone * (powerrighttwo / powerrightthree);
			float powerright = powerrightone * (powerrighttwo / powerrightthree);

			power = powerleft + powerright;

			float ccvalue = (float) Math.pow(10, power);
			Log.d("tag1", "ccvalue: " + ccvalue);
			componentvalues.add(ccvalue);
		}
		
		public static Bitmap exportFinalImage(){
			return valuesbmp;
		}



}
